from django.shortcuts import render, redirect
# 导包
from django.http import HttpResponse, HttpResponseRedirect, JsonResponse
# 导入类视图
from django.views import View

SECRET_KEY = 'asdkajk*12+adasd=mmlkvjjxuv'

# 码云client_id、client_secret
client_id = '58f78a1312dc723976e0818819ff61472d543297d91e9c589eaaab61c38e6484'
client_secret = '62578eb4fb8b19ce70ee7d1f4a34890be9d6e719af9c2683d898a5ebfa7c5ef8'

import json
from django.core.serializers import serialize
from rest_framework.response import Response
from rest_framework.views import APIView
# 导入加密库
import hashlib
# 导入图片库
# 绘画库
from PIL import ImageDraw
# 字体库
from PIL import ImageFont
# 图片库
from PIL import Image
# 随机库
import random
# 文件流
import io

import requests

# 导入上传文件夹配置
from mydjango.settings import UPLOAD_ROOT
import os

# 导入原生sql模块
from django.db import connection

import jwt

# 导入redis数据库
import redis

# 导入时间模块
import time

# 导入公共目录变量
from mydjango.settings import BASE_DIR

# 导包
from django.db.models import Q, F

# 导入dwebsocket的库
from dwebsocket.decorators import accept_websocket
import uuid

from myapp.models import User, Authorize

from django.utils.deprecation import MiddlewareMixin

from django.http import QueryDict

# 类视图调用
from django.utils.decorators import method_decorator

# 事务操作
from django.db import transaction

# 密码加密
# from django.contrib.auth.hashers import check_password, make_password

# 正则匹配
import re

# 导入时间模块儿
import datetime

from myapp.serializers import UserSer, AuthSer


import hmac
import base64
from hashlib import sha256
import urllib
import json

from practical_training.test_queue import MyQueue, RedisQueue, ThreadWork


# 钉钉路由
class DingLogin(APIView):

    def get(self, request):

        appid = 'dingoaukgkwqknzjvamdqh'
        redirect_uri = 'http://localhost:8000/ding_back/'

        return redirect('https://oapi.dingtalk.com/connect/qrconnect?appid='+appid+'&response_type=code&scope=snsapi_login&state=STATE&redirect_uri='+redirect_uri)


# 钉钉回调
class DingBack(APIView):

    def get(self, request):

        #获取code
        code = request.GET.get('code')

        t = time.time()
        #时间戳
        timestamp = str((int(round(t * 1000))))
        appSecret ='ly-AzMKMmCKQP3geaILT_An32kEfKO3HeOtApy5CgKwjytevVZC0WYsT2gxMB160'

        #构造签名
        signature = base64.b64encode(hmac.new(appSecret.encode('utf-8'),timestamp.encode('utf-8'), digestmod=sha256).digest())
        
        #请求接口，换取钉钉用户名
        payload = {'tmp_auth_code':code}
        headers = {'Content-Type': 'application/json'}
        res = requests.post('https://oapi.dingtalk.com/sns/getuserinfo_bycode?signature='+urllib.parse.quote(signature.decode("utf-8"))+"&timestamp="+timestamp+"&accessKey=dingoaukgkwqknzjvamdqh",data=json.dumps(payload),headers=headers)

        res_dict = json.loads(res.text)
        print(res_dict)
        # return HttpResponse(res_dict)
        
        # 判断
        user = User.objects.filter(username=res_dict['user_info']['nick']).first()

        if user:
            return redirect('http://localhost:8080/mylogin3?uid=' + str(user.id) + "&username=" + user.username)

        else:

            user = User(username=res_dict['user_info']['nick'])
            user.save()
            user_obj = User.objects.filter(username=res_dict['user_info']['nick']).first()

            return redirect('http://localhost:8080/mylogin3?uid=' + str(user_obj.id) + "&username=" + user_obj.username)


# 拼接码云三方url
class GiteeLogin(View):

    def get(self,request):

        return redirect('https://gitee.com/oauth/authorize?client_id='+client_id+'&redirect_uri=http://localhost:8000/gitee_back/&response_type=code&scope=user_info')


# 码云回调url
class GiteeBackBack(View):

    def get(self,request):

        code = request.GET.get("code",None)

        r = requests.post("https://gitee.com/oauth/token?grant_type=authorization_code&code="+code+"&client_id="+client_id+"&redirect_uri=http://localhost:8000/gitee_back/&client_secret="+client_secret)
        print(r.text)
        
        res_dict = json.loads(r.text)
        access_token = res_dict['access_token']

        s = requests.get("https://gitee.com/api/v5/user?access_token="+access_token)
        s_dict = json.loads(s.text)

        user = User.objects.filter(username=s_dict['name']).first()

        if user:

            return redirect('http://localhost:8080/mylogin_two?uid=' + str(user.id) + '&username=' + user.username)

        else:

            user = User(username=s_dict['name'])
            
            user.save()
            user_obj = User.objects.filter(username=s_dict['name']).first()

            return redirect('http://localhost:8080/mylogin_two?uid=' + str(user_obj.id) + '&username=' + user_obj.username)




# -----------------------------------------------------------------------------

power = 0b001
power1 = 0b011
power2 = 0b111

# 权限管理
class UserPower(APIView):

    def get(self, request):

        uid = request.GET.get('uid')

        if int(uid) & power2 != 0:
            return Response({'message': '您拥有该页面的访问权限', 'code': 200})
        else:
            return Response({'message': '您没有该页面的访问权限', 'code': 405})


# ---------------------------------------------------------------------------

# RBAC权限管理实现ABAC时间段权限
class GetUserInfo(APIView):

    def get(self, request):

        number = int(1)

        # 获取用户ID
        uid = request.GET.get('id')
        # 获取用户数据库信息
        user = User.objects.filter(id=uid).first()
        # 判断用户是否存在
        if user:
            if user.auth.id == number:
                return Response({'message': '超级管理员', 'auth': user.auth.id})
            else:
                # n_time = time.strftime("%H:%M:%S")
                # print(n_time)   # 18:02:03    xx:xx:xx

                # 范围时间
                # d_time = datetime.datetime.strptime(str(datetime.datetime.now().date()) + '9:00', '%Y-%m-%d%H:%M')
                # d_time1 = datetime.datetime.strptime(str(datetime.datetime.now().date()) + '18:00', '%Y-%m-%d%H:%M')

                red = redis.Redis()
                # red.set('1',d_time)
                # red.set('2',d_time1)
                # 当前时间
                n_time = datetime.datetime.now()

                start = red.get(1)
                s = str(start, 'utf-8')
                time1 = datetime.datetime.strptime(s, '%Y-%m-%d %H:%M:%S')
                
                end = red.get(2)
                e = str(end, 'utf-8')
                time2 = datetime.datetime.strptime(e, '%Y-%m-%d %H:%M:%S')

                # 判断当前时间是否在范围时间内
                if n_time > time1 and n_time < time2:
                    t = 1
                    return Response({'message': '普通用户', 'auth': user.auth.id, 't': t})
                else:
                    t = 0
                    return Response({'message': '普通用户', 'auth': user.auth.id, 't': t})
        else:
            return Response({'message': '用户不存在'})


# ---------------------------------------------------------

# 自定义中间件
class Middleware(MiddlewareMixin):

    def process_request(self, request):

        num = int(request.GET.get('uid'))
    
        if num % 2 != 0:

            if request.path != '/users/':
                return HttpResponse(json.dumps({'message':'您没有该页面的访问权限','code':400},ensure_ascii=False))
            else:
                # return HttpResponseRedirect('/users/')
                pass
        else:

            if request.path != '/userdetail/':
                return HttpResponse(json.dumps({'message':'您没有该页面的访问权限','code':400},ensure_ascii=False))
            else:
                # return HttpResponseRedirect('/userdetail/')
                pass


    def process_view(self, request, view_func, view_args, view_kwargs):
        pass

    def process_exception(self, request, exception):
        pass

    def process_response(self, request, response):
        
        return response






red = RedisQueue("redisqueue")


class PutUser(APIView):

    def post(self, request):

        ThreadWork()

        return Response({'message': '修改成功'})


# 存入redis  入队
class UpUser(APIView):

    def get(self, request):

        # 获取id
        uid = request.GET.get('id', None)
        # 获取用户名
        username = request.GET.get('username', None)

        # 判断数据库中有没有此用户
        user = User.objects.filter(username=username).first()
        if user:
            # 入队
            red.put((uid, username))

            return Response({'msg': '正在审核中，请耐心等待'})
        else:
            return Response({'msg': '没有此用户，无法进行修改用户名服务'})


# 出队
class GetInfo(APIView):

    def get(self, request):

        if red != None:
            # [red.pop() for i in range(100)]
            return Response(red.pop())
        
        else:
            return Response({'msg': '当前没有可以出队的数据'})


# ----------------------------------------------------------------------


myq = MyQueue()

class GetJob(APIView):

    def get(self, request):

        # 出队
        if myq.empty() == False:
            myjob = myq.pop()
            return Response(myjob)
        else:
            return Response({'msg': '当前没有可以出队的数据'})
        


# 修改用户名
class UpdateUserName(APIView):

    def get(self, request):

        # 获取id
        uid = request.GET.get('id', None)
        # 获取用户名
        username = request.GET.get('username', None)

        # 判断数据库中有没有此用户
        user = User.objects.filter(username=username).first()
        if user:
            # 入队
            myq.push((uid, username))

            return Response({'msg': '正在审核中，请耐心等待'})
        else:
            return Response({'msg': '没有此用户，无法进行修改用户名服务'})



# 构造课程分类层级关系(树)
def get_tree(data):

    lists = []
    tree = {}

    for item in data:
        tree[item['id']] = item

    for i in data:
        if not i['pid']:
            lists.append(tree[i['id']])
        else:
            parent_id = i['pid']
            if "children" not in tree[parent_id]:
                tree[parent_id]["children"] = []
            tree[parent_id]["children"].append(tree[i['id']])

    return lists



# 获取课程分类
def get_cate(request):
    # 建立查询游标
    cursor = connection.cursor()
    # 指行sql语句
    cursor.execute('SELECT * from cate')
    # 获取结果集
    res = dictfetchall(cursor)
    # 强转
    res=get_tree(res)
    return HttpResponse(json.dumps(res, indent=4, ensure_ascii=False), content_type='application/json')



# 添加课程
def add_course(request):

    # 获取参数
    course_name = request.POST.get('course_name')
    price = request.POST.get('price')
    user_id = request.POST.get('uid')
    pid = request.POST.get('cate_id')
    token = request.POST.get('token')

    decode_str = jwt.decode(token,'SECRET_KEY',algorithm=['HS256'])
    data = decode_str.get('data',0)
    uid = data.get('uid',0)

    if uid == user_id:
        # 建立添加游标
        cursor = connection.cursor()
        # 执行sql语句
        cursor.execute("insert into course(id,course_name,price,pid,user_id) values ('%s','%s','%s','%s','%s')" % (0,course_name,price,pid,user_id))

        return HttpResponse({'添加成功'})
    else:
        return HttpResponse({'405'})



# 列表推导式强转
def dictfetchall(cursor):

    desc = cursor.description

    return [

    dict(zip([col[0] for col in desc],row))

    for row in cursor.fetchall()

    ]


# 获取某个用户的权限
class GetUserAccess(View):

    def get(self, request):

        # uid = request.GET.get('uid',None)

        # # 建立查询游标
        # cursor = connection.cursor()
        # # 执行sql
        # cursor.execute('SELECT a.username,c.node_name,c.id from user a left join access b on a.id = b.uid left join node c on b.node_id = c.id where a.id = %s;' % uid)
        # # 获取结果集
        # res = cursor.fetchall()

        # return HttpResponse(json.dumps(res,ensure_ascii=False),content_type='application/json')

        # -------------------------------

        # 建立查询游标
        cursor = connection.cursor()
        # 执行sql语句
        cursor.execute('SELECT * from auth;')
        # 获取结果集
        # res = cursor.fetchall()
        res = dictfetchall(cursor)

        # 返回的是一个列表嵌套类型，前端渲染需注意  例：[[1, "用户中心"], [2, "修改密码"], [3, "上传头像"]]
        # return HttpResponse(json.dumps(res,ensure_ascii=False),content_type="application/json")
        return HttpResponse(json.dumps(res, indent=2, ensure_ascii=False),content_type="application/json")

    def post(self, request):

        # 获取数据
        uid = request.POST.get('uid')
        auth_id = request.POST.get('auth_id')


        # 逻辑判断与数据库
        # 1.1、先查询出uid对应的用户信息
        user_obj = User.objects.get(id=uid)

        # 1.2、查询出auth_id对应的权限信息
        auth_obj = Authorize.objects.get(id=auth_id)
        
        # 1.3、为这两个对象添加上关系
        # 1.3.1、为用户添加上对应的权限
        user_obj.u_auth.add(auth_obj)
        
        # 1.3.2、为权限添加上对应的用户
        auth_obj.access.add(user_obj)
        

        return HttpResponse({'ok'})



# 查看权限，例：没有上传头像权限不能上传头像
class GetAuth(APIView):
    def get(self, request):

        # 获取参数
        uid = request.GET.get('uid')
        
        user_obj = User.objects.get(pk=uid)
        auth_obj = user_obj.u_auth.all()

        ser_obj = AuthSer(auth_obj, many=True)

        return Response(ser_obj.data)



# 定义判断用户权限方法
user = 0b110
permission = 0b001

def my_decorator(func):

    def wrapper(request,*args,**kwargs):

        print('装饰器被调用')

        if user & permission:

            return func(request,*args,**kwargs)
        else:

            return HttpResponse('您没有权限')

    return wrapper

def up_loading(request):

    return HttpResponse('上传成功')




# 文件上传
class Uploader(View):

    def post(self, request):
        # 接收参数
        file = request.FILES.get("file")

        # 写入文件
        with open(os.path.join(UPLOAD_ROOT,'',file.name),'wb') as f:
            for chunk in file.chunks():
                f.write(chunk)

        return HttpResponse(json.dumps({'filename':file.name},ensure_ascii=False),content_type
            ='application/json')



# 定义验证码类
class MyCode(View):

    # 内置类方法
    def get_random_color(self):

        R = random.randrange(255)
        G = random.randrange(255)
        B = random.randrange(255)

        return (R,G,B)

    def get(self, request):

        # 定义画布
        img_size = (120,50)

        # 定义图像对象
        image = Image.new("RGB",img_size,'#BAC3BB')
        # 定义字体
        font_size = ImageFont.truetype('C:/Windows/Fonts/constani.ttf',30)
        # print(font)
        # 定义画笔
        draw = ImageDraw.Draw(image,"RGB")
        # 定义字符串
        source = '0123456789abcdefghgklmnopqrstuvwxyz'
        # 定义容器，用来接收随机字符串
        code_str = ''
        for i in range(4):
            # 获取字符颜色
            text_color = self.get_random_color()
            # 获取随机字符
            tmp_num = random.randrange(len(source))
            random_str = source[tmp_num]
            code_str += random_str
            # 用画笔把验证码画到图片上
            # 参数：xy:坐标，画在哪个位置；text:画的内容；text_color:画什么颜色；font:字体格式
            draw.text((10+25*i,10),random_str,text_color,font=font_size)

        buf = io.BytesIO()
        image.save(buf,'png')

        # 保存验证码
        # request.session['code'] = code_str
        r = redis.Redis()
        r.set('code',code_str)

        return HttpResponse(buf.getvalue(),'image/png')



# 重写加密方法
def make_password(mypass):

    # 生成对象
    md5 = hashlib.md5()
    # 定义加密对象
    sign_str = mypass
    # 转码
    sign_utf8 = str(sign_str).encode(encoding="utf-8")
    # 加密
    md5.update(sign_utf8)
    # 生成密文
    md5_server = md5.hexdigest()

    return md5_server



# 用户注册
class Register(APIView):
    def get(self, request):
        # 接收参数
        username = request.GET.get('username', None)
        password = request.GET.get('password', None)
        pwd = request.GET.get('pwd', None)
        phone = request.GET.get('phone', None)
        email = request.GET.get('email', None)
        password2 = make_password(password)

        if not all([username, password, pwd, phone, email]):
            return Response({'message': '请填写完整数据后提交！', 'code': 400})

        # 排重
        user = User.objects.filter(username=username).first()
        if user:
            res = {}
            res['code'] = 405
            res['message'] = '用户已经存在'
            return Response(res)

        if password != pwd:
            return Response({'message': '两次密码不一致', 'code': 400})

        phone_re = re.compile(r'^1(3\d|4[4-9]|5[0-35-9]|6[67]|7[013-8]|8[0-9]|9[0-9])\d{8}$')
        if not re.search(phone_re, phone):
            return Response({'message': '手机号不符合规范', 'code': 400})

        email_re = re.compile(r'^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$')
        if not re.search(email_re, email):
            return Response({'message': '邮箱格式不正确', 'code': 400})

        # 入库
        user = User(username=username, password=password2, phone=phone, email=email)
        user.save()
        return Response({'message': '注册成功', 'code': 200})

        # try:
        #     user = User(username=username, password=password)
        #     user.save()
        #     return Response({'message': '注册成功', 'code': 200})
        # except Exception as e:
        #     print(str(e))
        #     return Response({'message': '用户名已注册', 'code': 405})


# 用户登录
class Login(APIView):
    def get(self, request):
        # 获取数据
        username = request.GET.get('username', None)
        password = request.GET.get('password', None)

        # 检查数据
        user_obj = User.objects.filter(Q(username=username) | Q(phone=username) | Q(email=username)).first()

        if user_obj:
            pwd = check_password(password, user_obj.password)
            if pwd == True:
                return Response({'message': '登录成功', 'code': 200})
            else:
                return Response({'message': '用户名或密码错误', 'code': 400})
        else:
            return Response({'message': '用户不存在', 'code': 400})


# 登录接口
class LoginView(APIView):

    def post(self, request):
        username = request.data.get('username', None)
        password = request.data.get('password', None)
        phone = request.data.get('phone', None)
        email = request.data.get('email', None)
        active = request.data.get('active', None)
        code = request.data.get('code', None)
        
        # code_str = request.session.get('code', None)
        r = redis.Redis()
        code_s = r.get('code')
        code_str = str(code_s,'utf-8')
        print(code_str)


        if code == code_str:
            if active == '0':
                user = User.objects.filter(username=username, password=make_password(password)).first()

                if user:
                    payload = {
                        'exp':int((datetime.datetime.now()+datetime.timedelta(hours=10)).timestamp()),
                        'data':{
                            'uid':user.id,
                            'username':user.username
                        }
                    }
                    encode_jwt = jwt.encode(payload,'SECRET_KEY',algorithm='HS256')
                    encode_str = str(encode_jwt,'utf-8')
                    return Response({'message': '登录成功', 'code': 200,'username':user.username,
                        'token':encode_str,'uid':user.id})
                else:
                    return Response({'message': '用户名或密码错误', 'code': 400})
                
            
            elif active == '1':
                user = User.objects.filter(phone=phone, password=make_password(password)).first()
                if user:

                    payload = {
                        'exp':int((datetime.datetime.now()+datetime.timedelta(hours=10)).timestamp()),
                        'data':{
                            'uid':user.id,
                            'username':user.username
                        }
                    }
                    encode_jwt = jwt.encode(payload,'SECRET_KEY',algorithm='HS256')
                    encode_str = str(encode_jwt,'utf-8')
                    return Response({'message': '登录成功', 'code': 200,'username':user.username,
                        'token':encode_str,'phone':user.phone,'uid':user.id})
                else:
                    return Response({'message': '手机号或密码错误', 'code': 400})


            else:
                user = User.objects.filter(email=email, password=make_password(password)).first()
                if user:

                    payload = {
                        'exp':int((datetime.datetime.now()+datetime.timedelta(hours=10)).timestamp()),
                        'data':{
                            'uid':user.id,
                            'username':user.username
                        }
                    }
                    encode_jwt = jwt.encode(payload,'SECRET_KEY',algorithm='HS256')
                    encode_str = str(encode_jwt,'utf-8')
                    return Response({'message': '登录成功', 'code': 200,'username':user.username,
                        'token':encode_str,'email':user.email,'uid':user.id})
                else:
                    return Response({'message': '邮箱或密码错误', 'code': 400})
        else:
            return Response({'message': '验证码不正确,请重新输入', 'code': 400})


    def put(self, request):
        # 获取数据
        pwd = request.data.get('password')
        pwd2 = request.data.get('password2')
        token = request.data.get('token')
        uid = request.data.get('uid')
        username = request.data.get('username')

        # 数据逻辑判断
        # 解密
        decode_token = jwt.decode(token,'SECRET_KEY',algorithm=['HS256'])
        data = decode_str.get('data',0)
        uuid = data.get('uid',0)
        uname = data.get('username',0)
        
        
        if pwd != pwd2:
            return Response({'message':'两次密码不一致','code':400})

        else:
            user = User.objects.filter(id=uuid,username=uname).update(password=make_password(pwd))

            if user:
                return Response({'message':'修改成功','code':200})
            else:
                return Response({'message':'修改失败','code':400})


    def get(self, request):
        user_list = User.objects.all()
        user_ser = UserSer(user_list,many=True)

        return Response(user_ser.data)



#构造钉钉登录url
def ding_url(request):
    appid = 'dingoaukgkwqknzjvamdqh'
    redirect_uri = 'http://localhost:8000/dingding_back/'

    return redirect('https://oapi.dingtalk.com/connect/qrconnect?appid='+appid+'&response_type=code&scope=snsapi_login&state=STATE&redirect_uri='+redirect_uri)




#构造钉钉回调方法
def ding_back(request):

    #获取code
    code = request.GET.get("code")

    t = time.time()
    #时间戳
    timestamp = str((int(round(t * 1000))))
    appSecret ='ly-AzMKMmCKQP3geaILT_An32kEfKO3HeOtApy5CgKwjytevVZC0WYsT2gxMB160'
    #构造签名
    signature = base64.b64encode(hmac.new(appSecret.encode('utf-8'),timestamp.encode('utf-8'), digestmod=sha256).digest())
    #请求接口，换取钉钉用户名
    payload = {'tmp_auth_code':code}
    headers = {'Content-Type': 'application/json'}
    res = requests.post('https://oapi.dingtalk.com/sns/getuserinfo_bycode?signature='+urllib.parse.quote(signature.decode("utf-8"))+"&timestamp="+timestamp+"&accessKey=dingoaukgkwqknzjvamdqh",data=json.dumps(payload),headers=headers)

    res_dict = json.loads(res.text)
    print(res_dict)
    
    # 判断
    user = User.objects.filter(username=res_dict['user_info']['nick']).first()

    if user:

        return redirect('http://localhost:8080/mylogin_two?uid=' + str(user.id) + "&username=" + user.username)

    else:

        user = User(username=res_dict['user_info']['nick'])
        user.save()
        user_obj = User.objects.filter(username=res_dict['user_info']['nick']).first()

        return redirect('http://localhost:8080/mylogin_two?uid=' + str(user_obj.id) + "&username=" + user_obj.username)



# 拼接码云三方url
class Gitee(View):

    def get(self,request):

        return redirect('https://gitee.com/oauth/authorize?client_id='+client_id+'&redirect_uri=http://localhost:8000/gitee_back/&response_type=code&scope=user_info')


# 码云回调url
class GiteeBack(View):

    def get(self,request):

        code = request.GET.get("code",None)

        r = requests.post("https://gitee.com/oauth/token?grant_type=authorization_code&code="+code+"&client_id="+client_id+"&redirect_uri=http://localhost:8000/gitee_back/&client_secret="+client_secret)
        print(r.text)
        
        res_dict = json.loads(r.text)
        access_token = res_dict['access_token']

        s = requests.get("https://gitee.com/api/v5/user?access_token="+access_token)
        s_dict = json.loads(s.text)

        user = User.objects.filter(username=s_dict['name']).first()

        if user:

            return redirect('http://localhost:8080/mylogin_two?uid=' + str(user.id) + '&username=' + user.username)

        else:

            user = User(username=s_dict['name'])
            
            user.save()
            user_obj = User.objects.filter(username=s_dict['name']).first()

            return redirect('http://localhost:8080/mylogin_two?uid=' + str(user_obj.id) + '&username=' + user_obj.username)






